#include "ctagdata.h"

#include <QDebug>
#include <QtEndian>
#include <QDateTime>

CTagData::CTagData(QObject *parent)
    : QObject(parent)
{
    m_nIndex = 0;
    m_nDataType = enUint8;
    m_nScanRate = 1000;
    m_sDataAccess = "R";
    m_dDeadband = 0.00;
	m_nExceptionReport = 0;
    m_nQuality = Q_DATAERR;
    m_nTimeStamp = 0;
    m_nDataSize = 0;
    m_nTimeStamp = QDateTime::currentMSecsSinceEpoch();
    value.un64Num = 0;
}

CTagData::CTagData(const CTagData& other, QObject* parent /*= nullptr*/)
    : QObject(parent),
    m_nIndex(other.m_nIndex),
    m_sTagName(other.m_sTagName),
    m_sTagDesc(other.m_sTagDesc),
    m_sAddr(other.m_sAddr),
    m_nDataType(other.m_nDataType),
    m_nScanRate(other.m_nScanRate),
    m_sDataAccess(other.m_sDataAccess),
    m_sCollectDrv(other.m_sCollectDrv),
    m_sCollectAddr(other.m_sCollectAddr),
    m_sKeyAddr(other.m_sKeyAddr),
    m_dDeadband(other.m_dDeadband),
    m_nExceptionReport(other.m_nExceptionReport),
    m_nQuality(other.m_nQuality),
    m_nTimeStamp(other.m_nTimeStamp),
    m_nDataSize(other.m_nDataSize)
{
    copyUnionValue(other);
}

CTagData& CTagData::operator=(const CTagData& other)
{
	if (this != &other) 
	{
		// 复制基本类型成员
		m_nIndex = other.m_nIndex;
		m_sTagName = other.m_sTagName;
		m_sTagDesc = other.m_sTagDesc;
		m_sAddr = other.m_sAddr;
		m_nDataType = other.m_nDataType;
		m_nScanRate = other.m_nScanRate;
		m_sDataAccess = other.m_sDataAccess;
		m_sCollectDrv = other.m_sCollectDrv;
		m_sCollectAddr = other.m_sCollectAddr;
		m_sKeyAddr = other.m_sKeyAddr;
		m_dDeadband = other.m_dDeadband;
		m_nExceptionReport = other.m_nExceptionReport;
		m_nQuality = other.m_nQuality;
		m_nTimeStamp = other.m_nTimeStamp;
		m_nDataSize = other.m_nDataSize;

		// 释放原有联合体资源
		if (m_nDataType == enString && value.str) 
		{
			delete[] value.str;
			value.str = nullptr;
		}

		// 复制联合体
		copyUnionValue(other);
	}
	return *this;
}

CTagData::~CTagData()
{
	if (m_nDataType == enString && value.str)
	{
		delete[] value.str;
		value.str = nullptr;
	}
}

void CTagData::setString(const QString &val)
{
    if (enString != m_nDataType) return;
    int nSize = val.size();
    if (128 < nSize) nSize = 128;
    if (0 != setDataSize(nSize)) return;
    memcpy(value.str, val.toLatin1().data(), nSize);
}

void CTagData::setString(const QByteArray &byte)
{
    if (enString != m_nDataType) return;
    int nSize = byte.size();
    if (128 < nSize) nSize = 128;
    if (0 != setDataSize(nSize)) return;
    memcpy(value.str, byte.data(), nSize);
}

void CTagData::setBEData(quint64 nData)
{
    QMutexLocker locker(&m_mutex);
    MyUnion uValue;
    memcpy(&uValue, &nData, sizeof(quint64));
    value.un64Num = 0;
    switch (m_nDataType)
    {
    case CTagData::enUint8:
        setUint8(uValue.byte);
        break;
    case CTagData::enUint16:
        setUint16(qFromBigEndian<quint16>(uValue.un16Num));
        break;
    case CTagData::enInt16:
        setInt16(qFromBigEndian<qint16>(uValue.n16Num));
        break;
    case CTagData::enUint32:
        setUint32(qFromBigEndian<quint32>(uValue.un32Num));
        break;
    case CTagData::enInt32:
        setInt32(qFromBigEndian<qint32>(uValue.n32Num));
        break;
    case CTagData::enUint64:
        setUint64(qFromBigEndian<quint64>(uValue.un64Num));
        break;
    case CTagData::enInt64:
        setInt64(qFromBigEndian<qint64>(uValue.n64Num));
        break;
    case CTagData::enFloat:
        setFloat(getFloatFromBEUnion(uValue.un32Num));
        break;
    case CTagData::enDouble:
        setDouble(getDoubleFromBEUnion(uValue.un64Num));
        break;
    default:
        break;
    }
}

int CTagData::setDataSize(const int &nSize)
{
	if (enString != m_nDataType) return -1;
	if (128 < nSize) return -2;
    if (nSize < m_nDataSize) return 0;
	//释放之前内存
    if (0 != m_nDataSize && value.str != nullptr)
	{
		delete[] value.str;
		value.str = nullptr;
	}
    if (nSize == 0)
    {
        m_nDataSize = 0;
        return 0;
    }
	m_nDataSize = nSize;
	value.str = new char[nSize];
	memset(value.str, 0, m_nDataSize);
	return 0;
}

void CTagData::setValue(const double &val, const uint64_t &tStamp)
{
    value.dNum = val;
    m_nTimeStamp = tStamp;
    m_nQuality = Q_GOOD;
}

void CTagData::setValue(const double &val)
{
    value.dNum = val;
    m_nTimeStamp = getTimeStamp();
    m_nQuality = Q_GOOD;
}

int CTagData::setValue(const CTagData &dest)
{
	//if(0 == strcmp(sAddr, dest.sAddr)) return -1;
	m_nDataType = dest.m_nDataType;
	m_nTimeStamp = dest.m_nTimeStamp;
	if (enString != dest.m_nDataType)
		value = dest.value;
	else
	{
		setDataSize(dest.m_nDataSize);
		memcpy(value.str, dest.value.str, m_nDataSize);
	}
	m_nQuality = dest.m_nQuality;
	return 0;

}

int CTagData::setValue(const CTagData* &dest)
{
	m_nDataType = dest->m_nDataType;
	m_nTimeStamp = dest->m_nTimeStamp;
	if (enString != dest->m_nDataType)
		value = dest->value;
	else
	{
		setDataSize(dest->m_nDataSize);
		memcpy(value.str, dest->value.str, m_nDataSize);
	}
	m_nQuality = dest->m_nQuality;
	return 0;

}

void CTagData::getValue(double *val)
{
    QMutexLocker locker(&m_mutex);
	*val = value.dNum;
	return;
}

void CTagData::getValue(std::string &sVal)
{
    QMutexLocker locker(&m_mutex);
    sVal = value.str;
}

void CTagData::copyTag(CTagData *pTag)
{
    if (pTag == nullptr) return;
    m_nIndex = pTag->m_nIndex;
    m_sTagName = pTag->m_sTagName;
    m_sTagDesc = pTag->m_sTagDesc;
    m_sAddr = pTag->m_sAddr;
    m_nDataType = pTag->m_nDataType;
    m_nScanRate = pTag->m_nScanRate;
    m_sDataAccess = pTag->m_sDataAccess;
    m_sCollectDrv = pTag->m_sCollectDrv;
    m_sCollectAddr = pTag->m_sCollectAddr;
    m_sKeyAddr = pTag->m_sKeyAddr;
    m_dDeadband = pTag->m_dDeadband;
    m_nExceptionReport = pTag->m_nExceptionReport;
}

void CTagData::copyUnionValue(const CTagData& other)
{
	if (other.m_nDataType == enString && other.value.str)
	{
		m_nDataSize = other.m_nDataSize;
		value.str = new char[m_nDataSize + 1];
		strncpy(value.str, other.value.str, m_nDataSize);
		value.str[m_nDataSize] = '\0';
	}
	else 
	{
		memcpy(&value, &other.value, sizeof(value));
    }
}

float CTagData::getFloatFromBEUnion(quint32 nIn)
{
    quint32 nValue = qFromBigEndian<quint32>(nIn);
    float fValue = 0.00f;
    memcpy(&fValue, &nValue, 4);
    return fValue;
}

double CTagData::getDoubleFromBEUnion(quint64 nIn)
{
    quint64 nValue = qFromBigEndian<quint64>(nIn);
    double dValue = 0.00f;
    memcpy(&dValue, &nValue, 8);
    return dValue;
}
